Skip to content

ci: run E2E suites in demo apps (Android) - #381

Open
alpharius-ck wants to merge 44 commits into
mainfrom
e2e-for-android
Open

ci: run E2E suites in demo apps (Android)#381
alpharius-ck wants to merge 44 commits into
mainfrom
e2e-for-android

Conversation

@alpharius-ck

@alpharius-ck alpharius-ck commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds and stabilizes Android Detox E2E for the brownfield demo apps (AndroidApp + embedded RN hosts), covering vanilla, Expo 56, and Expo 57.

CI pipeline

  • Vanilla — single job: package AAR → Detox APKs → E2E (120 min).
  • Expo 56 / Expo 57 — split build + test jobs (avoids timeouts):
  • android-androidapp-expo{56,57}-build — package AAR, Detox build, upload APK artifact (120 min)
  • android-androidapp-expo{56,57}-e2e — download APKs, boot emulator, run Detox (90 min)
  • androidapp-road-test supports e2e-phase: none | full | build | test

E2E reliability (Expo on Android)

Headless CI emulators often break Espresso/Detox sync and clipped NativeTabs taps. This PR hardens shared helpers around:

  • UIAutomator-first readiness / assertions (adb) where Espresso visibility is flaky
  • Resolution-aware shell scrolling
  • PostMessage tab open via UIAutomator + icon-biased tap (sync off), with member Brownie APIs (no fat-AAR package-level extension imports)
  • Shared Expo suite for 56 and 57 (androidAppExpoBrownfield.e2e.js)

@artus9033 artus9033 mentioned this pull request Jun 23, 2026
3 tasks
@alpharius-ck
alpharius-ck marked this pull request as ready for review June 30, 2026 07:18
Comment thread .github/workflows/ci.yml Outdated
Comment on lines +15 to +18
class BrownfieldApplication : Application(), ReactApplication {
@Suppress("DEPRECATION")
override val reactNativeHost: ReactNativeHost
get() = ReactNativeHostManager.reactNativeHost

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you need to declare reactNativeHost only because of Expo54 as it contains the deprecated API usage.

If yes, then we can hold this PR until we remove Expo54, which will be done soon after #360

The reason I am suggesting to hold this PR is because we are shipping deprecated stuff as part of Expo config plugin for apps above SDK 54 and they do not require it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the reactNativeHost override in BrownfieldApplication is effectively required for Expo 54 Detox; for Expo 55 and vanilla, reactHost is sufficient and matches RN’s direction (same as Detox #4895 around New Architecture).

Config plugin vs test app:

The deprecated pre55 template (ReactNativeHostWrapper, etc.) is only generated for Expo < 55 — not for SDK 55+ consumers.
BrownfieldApplication lives in the example AndroidApp, not in the published library API.
On holding until #360: Reasonable if the goal is zero deprecated surface before merge. Counter-arguments for merging now:

Android E2E targets Vanilla + Expo 55; Expo 54 is road-test only (no E2E).
We could drop the reactNativeHost override from shared BrownfieldApplication and move it to an expo54 flavor-specific source set once #360 lands, leaving reactHost only for 55+.
Proposed path: Merge E2E for 55/vanilla now, or gate on #360 — your call. If we proceed, a follow-up to flavor-split BrownfieldApplication (expo54 vs 55+) would address the deprecated API concern without blocking E2E.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the response, appreciate it. I would prefer to hold this PR until end of this week, in the meantime, we will get SDK 56 support merged and SDK 54 apps removal. Then we can rebase this PR and get rid of deprecated API stuff and get it merged.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me thanks!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alpharius-ck - Since we only have SDK 56 and 57 supported, we can remove this deprecated API stuff.

…roid/example/BrownfieldApplication.kt

Co-authored-by: Hur Ali <hurali97@gmail.com>
@alpharius-ck
alpharius-ck requested a review from hurali97 June 30, 2026 14:04
@alpharius-ck

Copy link
Copy Markdown
Collaborator Author

@hurali97 @artus9033 ready for the final review

@artus9033

Copy link
Copy Markdown
Collaborator

CC @hurali97 - would you review?

@artus9033 artus9033 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Comment on lines +119 to +135
val reactHost = ReactNativeBrownfield.shared.reactHost
reactHost.currentReactContext?.let {
Toast.makeText(this, "React Native has been loaded", Toast.LENGTH_LONG).show()
return
}

reactHost.addReactInstanceEventListener(object : ReactInstanceEventListener {
override fun onReactContextInitialized(context: ReactContext) {
Toast.makeText(
this@MainActivity,
"React Native has been loaded",
Toast.LENGTH_LONG
).show()
reactHost.removeReactInstanceEventListener(this)
}
})
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Why do we need to reinvent this block? Why we cant use the following removed block?

           ReactNativeHostManager.initialize(application) {
                Toast.makeText(
                    this,
                    "React Native has been loaded",
                    Toast.LENGTH_LONG
                ).show()
            }

Comment on lines +7 to +16
import com.facebook.react.ReactNativeHost

object ReactNativeHostManager {
@Suppress("DEPRECATION")
val reactNativeHost: ReactNativeHost
get() =
throw RuntimeException(
"You should not use ReactNativeHost directly in the New Architecture"
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe if you remove the deprecation related code usage from Android App you wont need to make this change._

Comment on lines +13 to +18
@Suppress("DEPRECATION")
val reactNativeHost: ReactNativeHost
get() =
throw RuntimeException(
"You should not use ReactNativeHost directly in the New Architecture"
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants